package com.web.server.common.utils;

import org.apache.log4j.Logger;
import org.springframework.util.StringUtils;

import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.Map.Entry;

/**
 * Created by ZHANGXIANLIANG1 on 2016/2/22.
 * 配置文件读取工具类
 */
public class ConfigUtil {
    private static final Logger RUN_LOG = Logger.getLogger(ConfigUtil.class);

    // 忽略属性文件列表，与列表中相同名称的属性文件将不被加载
    private static final List<String> IGNORE_CONFIG_FILES = new ArrayList<String>(Arrays.asList("log4j.properties"));
    // 非属性文件列表，与列表中相同文件名称的非属性文件，将被保存在 NONE_PROPERTY_FILES 文件列表中
    private static final List<String> NONE_PROPERTY_FILE_SUFFIX = new ArrayList<String>( Arrays.asList(".template") );

    // 全局配置信息
    private static final Properties config = new Properties();
    private static final Map<String, File> NONE_PROPERTY_FILES= new HashMap<String, File>();

    // 一次性加载所有配置文件中的信息
    static {
        try (Reader reader = new InputStreamReader(ConfigUtil.class.getClassLoader().getResourceAsStream("config.properties"), "UTF-8")) {
            URL url = ConfigUtil.class.getClassLoader().getResource("////");
            if (url == null) {
                url = ConfigUtil.class.getClassLoader().getResource("//");
            }
            String clazzPath = url == null ? null : url.getPath();
            if (url != null && clazzPath.contains("test-classes")) {
                clazzPath = clazzPath.replace("test-classes", "classes");
            }
            if (url == null) {
                RUN_LOG.error("Wrong! Properties file's dir is Not Found!");
            }
            RUN_LOG.info("Start to load all property files in director: " + clazzPath);

            loadConfig(clazzPath);
        } catch (Exception e) {
            RUN_LOG.error(e.getMessage(), e);
        }
    }

    /**
     * 一次性读取所有配置文件
     */
    private static void loadConfig(String filePath) {
        File tempFile = new File(filePath);

        if (tempFile.isDirectory()) {
            for (String tempFilePath : tempFile.list()) {
                loadConfig(filePath.concat(File.separator).concat(tempFilePath));
            }
        } else if (tempFile.isFile() && tempFile.getName().endsWith(".properties") && !IGNORE_CONFIG_FILES.contains(tempFile.getName())) {
            try (BufferedReader inputStream = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "utf8"))) {
                config.load(inputStream);
                RUN_LOG.info("Load Properties File: ".concat(filePath));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                throw new RuntimeException("config.properties 文件不存在！", e);
            } catch (IOException e) {
                e.printStackTrace();
                throw new RuntimeException("config.properties 读取失败！", e);
            }
        } else if (tempFile.isFile() && NONE_PROPERTY_FILE_SUFFIX.contains(tempFile.getName().substring(tempFile.getName().lastIndexOf("."))) && !IGNORE_CONFIG_FILES.contains(tempFile.getName())) {
            if (NONE_PROPERTY_FILES.keySet().contains(tempFile.getName())) {
                RUN_LOG.warn(String.format("NONE_PROPERTY_FILE [%s] is already loaded, and [%s] is ignored!", NONE_PROPERTY_FILES.get(tempFile.getName()).getAbsolutePath(), tempFile.getAbsolutePath()));
            } else {
                NONE_PROPERTY_FILES.put(tempFile.getName(), tempFile);
            }
        }
    }

    // 禁止实例化
    private ConfigUtil() throws Exception {
        throw new IllegalAccessException("ConfigUtil Need Not Instantiation!");
    }

    /**
     * 按key获取一个属性
     *
     * @param key 属性的key值
     * @return 属性的真实值
     */
    public static String getProperty(String key) {
        return config.getProperty(key);
    }

    /**
     * 获取具有相同前缀的键的属性列表
     * @param keyPrefix 配置的键的前缀
     * @return 具有相同前缀的键的属性列表
     */
    public static Map<String, String> getPropertiesWithKeyStarts(String keyPrefix) {
        Map<String, String> props = new HashMap<String, String>();
        for (Entry<Object, Object> entry : config.entrySet()) {
            if (((String) entry.getKey()).startsWith(keyPrefix)) {
                props.put(entry.getKey().toString(), entry.getValue().toString());
            }
        }
        return props;
    }

    /**
     * 获取具有相同后缀的键的属性列表
     * @param keySuffix 配置的键的后缀
     * @return 具有相同后缀的键的属性列表
     */
    public static Map<String, String> getPropertiesWithKeyEnds(String keySuffix) {
        Map<String, String> props = new HashMap<String, String>();
        for (Entry<Object, Object> entry : config.entrySet()) {
            if (((String) entry.getKey()).endsWith(keySuffix)) {
                props.put(entry.getKey().toString(), entry.getValue().toString());
            }
        }
        return props;
    }

    /**
     * 获取匹配正则式的所有属性列表
     * @param keyRegex 属性key的正则式
     * @return 所有匹配正则式的属性列表
     */
    public static Map<String, String> getPropertiesWithKeyMatches(String keyRegex) {
        Map<String, String> props = new HashMap<String, String>();
        for (Entry<Object, Object> entry : config.entrySet()) {
            if (((String) entry.getKey()).matches(keyRegex)) {
                props.put(entry.getKey().toString(), entry.getValue().toString());
            }
        }
        return props;
    }

    /**
     * 根据文件名获取已配置的非属性文件
     */
    public static File getNonePropertyFile(String key) {
        return NONE_PROPERTY_FILES.get(key);
    }
}
